deferred class CD_CANVAS_COORDINATE_SYSTEM

inherit
	CANVAS_DRAW

feature {ANY}

	get_size_pixels: TUPLE[INTEGER, INTEGER]
		-- Returns the canvas size in pixels.
		local
			p: POINTER
			ix, iy: INTEGER
			tup: TUPLE[INTEGER, INTEGER]
		do
			int_canvas_get_size(cnvs, $ix, $iy, p, p)
			tup := [ix, iy]

			Result := tup
		end

	get_size_millimeters: TUPLE[REAL_64, REAL_64]
		-- Returns the canvas size in millimeters.
		local
			p: POINTER
			ix, iy: REAL_64
			tup: TUPLE[REAL_64, REAL_64]
		do
			int_canvas_get_size(cnvs, p, p, $ix, $iy)
			tup := [ix, iy]

			Result := tup
		end

	update_y_axis (y: INTEGER): INTEGER
		-- Invert the given Y coordinate if the native Y axis orientation is 
		-- different from the CD axis orientation. The CD axis orientation is 
		-- always bottom-top.
		local
			yc: INTEGER
		do
			yc := y
			
			Result := int_canvas_update_y_axis(cnvs, $yc)
		end

	invert_y_axis (y: INTEGER): INTEGER
		--	Invert the given Y coordinate independent of the driver Y axis 
		--	orientation.
		do
			Result := int_canvas_invert_y_axis(cnvs, y)
		end

	convert_mm_to_pixels (mmx, mmy: REAL_64): TUPLE[INTEGER, INTEGER]
		-- Converts sizes in millimeters into pixels (canvas coordinates). 
		-- Return integer values.
		local
			px, py: INTEGER
			tup: TUPLE[INTEGER, INTEGER]
		do
			int_canvas_mm_to_pixels(cnvs, mmx, mmy, $px, $py)

			tup := [px, py]
			Result := tup
		end

	convert_mm_to_pixels_real (mmx, mmy: REAL_64): TUPLE[REAL_64, REAL_64]
		-- Converts sizes in millimeters into pixels (canvas coordinates). 
		-- Return real 64 values.
		local
			px, py: REAL_64
			tup: TUPLE[REAL_64, REAL_64]
		do
			int_canvas_c_double_mm_to_pixels(cnvs, mmx, mmy, $px, $py)

			tup := [px, py]
			Result := tup
		end

	convert_pixels_to_mm (px, py: INTEGER): TUPLE[REAL_64, REAL_64]
		-- Converts sizes in pixels (canvas coordinates as integer values) into 
		-- millimeters. Use this function to obtain the horizontal and vertical 
		-- resolution of the canvas by passing 1 as parameter in dx and dy. The 
		-- resolution value is obtained using the formula res=1.0/mm.
		local
			mmx, mmy: REAL_64
			tup: TUPLE[REAL_64, REAL_64]
		do
			int_canvas_pixels_to_mm(cnvs, px, py, $mmx, $mmy)

			tup := [mmx, mmy]
			Result := tup
		end

	convert_pixels_to_mm_real (px, py: REAL_64): TUPLE[REAL_64, REAL_64]
		-- Converts sizes in pixels (canvas coordinates as real 64 values) into 
		-- millimeters. Use this function to obtain the horizontal and vertical 
		-- resolution of the canvas by passing 1 as parameter in dx and dy. The 
		-- resolution value is obtained using the formula res=1.0/mm.	
		local
			mmx, mmy: REAL_64
			tup: TUPLE[REAL_64, REAL_64]
		do
			int_canvas_c_double_pixels_to_mm(cnvs, px, py, $mmx, $mmy)

			tup := [mmx, mmy]
			Result := tup
		end

	set_origin (x, y: INTEGER)
		-- Allows translating the origin - for instance, to the center of the 
		-- canvas. The function profits from the architecture of the library to 
		-- simulate a translation of the origin, which in fact is never actually 
		-- passed to the canvas in the respective driver. It is not related with 
		-- WD nor Transformation Matrix. Default values: (0, 0)
		do
			int_canvas_origin(cnvs, x, y)
		end

	set_origin_real (x, y: REAL_64)
		-- As "set_origin" but the parematers are real 64 values.
		do
			int_canvas_c_double_origin(cnvs, x, y)
		end

	get_origin: TUPLE[INTEGER, INTEGER]
		-- Return the origin as integer values.
		local
			x, y: INTEGER
		do
			int_canvas_get_origin(cnvs, $x, $y)

			Result := [x, y]
		end

	get_origin_real: TUPLE[REAL_64, REAL_64]
		-- Return the origin as real 64 values.
		local
			x, y: REAL_64
		do
			int_canvas_c_double_get_origin(cnvs, $x, $y)

			Result := [x, y]
		end

	-- Transformation matrix

	set_transform (matrix: TUPLE[REAL_64, REAL_64, REAL_64, REAL_64, REAL_64, REAL_64])
		-- Defines a transformation matrix with 6 elements. If the matrix is 
		-- Void,	the transformation is reset to the identity. Default value: Void.
		--
		-- The matrix contains scale (sx,sy), rotation (angle) and translation 
		-- (dx,dy) elements as follows:
		--
		-- matrix[0] = sx*cos(angle)  // Horizontal Scale and Rotation component
		-- matrix[1] =    sin(angle)  // Rotation component (can also contain an 
		--                               horizontal shear component)
		-- matrix[2] =   -sin(angle)  // Rotation component (can also contain a 
		--                               vertical shear component)
		-- matrix[3] = sy*cos(angle)  // Vertical Scale and Rotation component
		-- matrix[4] = dx             // Horizontal Translation component
		-- matrix[5] = dy             // Vertical Translation component
		--
		-- Functions that retrieve images from the canvas are not affected by the 
		-- transformation matrix, such as "get_image", "get_image_rgb" and 
		-- "scroll_area".
		--
		-- Transformation matrix is independent of the World Coordinate and 
		-- Origin functions. And those are affected if a transformation is set, 
		-- just like other regular primitives.
		--
		-- The transformation matrix and world coordinates perform similar 
		-- functions. World coordinates were developed before the transformation 
		-- matrix support. The transformation matrix operates at a lower level 
		-- than world coordinates, and, as such, might be faster, but might 
		-- behave differently on different platforms. World coordinates behave 
		-- consistently across platforms.
		local
			m: ARRAY[REAL_64]
		do
			create m.make_filled((0).to_double, 1, 6 + 1)

         m.put(matrix.real_64_item(1), 1)
			m.put(matrix.real_64_item(2), 2)
			m.put(matrix.real_64_item(3), 3)
			m.put(matrix.real_64_item(4), 4)
			m.put(matrix.real_64_item(5), 5)
			m.put(matrix.real_64_item(6), 6)

			int_canvas_transform(cnvs, get_pointer(m.to_c))
		end

	get_transform: TUPLE[REAL_64, REAL_64, REAL_64, REAL_64, REAL_64, REAL_64]
			-- Returns the transformation matrix. If the identity is set, 
			-- returns Void.
		local
			p: POINTER
			m: MANAGED_POINTER
		do
			p := int_canvas_get_transform(cnvs)

			if p /= default_pointer then

				create m.make_from_pointer(p, 6)

				Result := [m.read_real_64(0), m.read_real_64(1), m.read_real_64(2), m.read_real_64(3), m.read_real_64(4), m.read_real_64(5)]
			else
				io.put_string("Something goes wrong %N")
				Result := [(0).to_double, (0).to_double, (0).to_double, (0).to_double, (0).to_double, (0).to_double]
			end
		end

	apply_transform_multiply (matrix: TUPLE[REAL_64, REAL_64, REAL_64, REAL_64])
		-- Left multiply the current transformation by the given transformation.
		local
			m: ARRAY[REAL_64]
		do
			create m.make_filled((0).to_double, 1, 4 + 1)

			m.put(matrix.real_64_item(1), 1)
			m.put(matrix.real_64_item(2), 2)
			m.put(matrix.real_64_item(3), 3)
			m.put(matrix.real_64_item(4), 4)

			int_canvas_transform_multiply(cnvs, get_pointer(m.to_c))
		end

	apply_transform_translate (dx, dy: REAL_64)
		-- Applies a translation to the current transformation.
		do
			int_canvas_transform_translate(cnvs, dx, dy)
		end

	apply_transform_scale (sx, sy: REAL_64)
		-- Applies a scale to the current transformation.
		do
			int_canvas_transform_scale(cnvs, sx, sy)
		end

	apply_transform_rotate (angle: REAL_64)
		-- Applies a rotation to the current transformation. Angle is in degrees, 
		-- oriented counter-clockwise from the horizontal axis.
		do
			int_canvas_transform_rotate(cnvs, angle)
		end

	transform_point (x, y: INTEGER): TUPLE[INTEGER, INTEGER]
		-- Applies a transformation to a given point.
		local
			tx, ty: INTEGER
		do
			int_canvas_transform_point(cnvs, x, y, $tx, $ty)

			Result := [tx, ty]
		end

	transform_point_real (x, y: REAL_64): TUPLE[REAL_64, REAL_64]
		-- Like "transform_point" but with REAL_64 values.
		local
			tx, ty: REAL_64
		do
			int_canvas_c_double_transform_point(cnvs, x, y, $tx, $ty)

			Result := [tx, ty]
		end

feature {NONE}

	int_canvas_get_size (wgt: POINTER; x, y, xm, ym: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasGetSize ($wgt, $x, $y, $xm, $ym);"
      end

	int_canvas_update_y_axis (wgt, y: POINTER): INTEGER
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"return cdCanvasUpdateYAxis ($wgt, $y);"
      end

	int_canvas_invert_y_axis (wgt: POINTER; yc: INTEGER): INTEGER
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"return cdCanvasInvertYAxis ($wgt, $yc);"
      end

	int_canvas_mm_to_pixels (wgt: POINTER; mm_x, mm_y: REAL_64; cx, cy: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasMM2Pixel ($wgt, $mm_x, $mm_y, $cx, $cy);"
      end

	int_canvas_c_double_mm_to_pixels (wgt: POINTER; mm_x, mm_y: REAL_64; cx, cy: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdfCanvasMM2Pixel ($wgt, $mm_x, $mm_y, $cx, $cy);"
      end

	int_canvas_pixels_to_mm (wgt: POINTER; p_x, p_y: INTEGER; cx, cy: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasPixel2MM ($wgt, $p_x, $p_y, $cx, $cy);"
      end

	int_canvas_c_double_pixels_to_mm (wgt: POINTER; p_x, p_y: REAL_64; cx, cy: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdfCanvasPixel2MM ($wgt, $p_x, $p_y, $cx, $cy);"
      end

	int_canvas_origin (wgt: POINTER; x, y: INTEGER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasOrigin ($wgt, $x, $y);"
      end

	int_canvas_c_double_origin (wgt: POINTER; x, y: REAL_64)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdfCanvasOrigin ($wgt, $x, $y);"
      end

	int_canvas_get_origin (wgt, x, y: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasGetOrigin ($wgt, $x, $y);"
      end

	int_canvas_c_double_get_origin (wgt, x, y: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdfCanvasGetOrigin ($wgt, $x, $y);"
      end

	int_canvas_transform (wgt, m: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasTransform ($wgt, $m);"
      end

	int_canvas_get_transform (wgt: POINTER): POINTER
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"return cdCanvasGetTransform ($wgt);"
      end

	int_canvas_transform_multiply (wgt, m: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasTransformMultiply ($wgt, $m);"
      end

	int_canvas_transform_translate (wgt: POINTER; dx, dy: REAL_64)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasTransformTranslate ($wgt, $dx, $dy);"
      end

	int_canvas_transform_scale (wgt: POINTER; sx, sy: REAL_64)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasTransformScale ($wgt, $sx, $sy);"
      end

	int_canvas_transform_rotate (wgt: POINTER; ang: REAL_64)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasTransformRotate ($wgt, $ang);"
      end

	int_canvas_transform_point (wgt: POINTER; x, y: INTEGER; tx, ty: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdCanvasTransformPoint ($wgt, $x, $y, $tx, $ty);"
      end

	int_canvas_c_double_transform_point (wgt: POINTER; x, y: REAL_64; tx, ty: POINTER)
		external
			"C inline use %"eiffel-iup.h%""
      alias
			"cdfCanvasTransformPoint ($wgt, $x, $y, $tx, $ty);"
      end

end

-- The MIT License (MIT)

-- Copyright (c) 2016, 2017, 2019, 2020 by German A. Arias

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in 
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
